﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using UnityEngine;

public class CityScore
{
    private City city;

    private float score = 0;

    private Dictionary<string, Dictionary<string, int>> lowerDifficultyInteractions = new Dictionary<string, Dictionary<string, int>>();
    private Dictionary<string, Dictionary<string, int>> upperDifficultyInteractions = new Dictionary<string, Dictionary<string, int>>();

    private int deteriorationStart = 15;

    private Dictionary<Vector2, float> interactionScoresByTile = new Dictionary<Vector2, float>();

    public float prisonDeteriorationPenalty = 0;
    public float foodDeteriorationPenalty = 0;

    public Dictionary<Vector2, float> policeDeteriorationByTile = new Dictionary<Vector2, float>();
    public Dictionary<Vector2, float> fireDeteriorationByTile = new Dictionary<Vector2, float>();
    public Dictionary<Vector2, float> hospitalDeteriorationByTile = new Dictionary<Vector2, float>();
    public Dictionary<Vector2, float> waterDeteriorationByTile = new Dictionary<Vector2, float>();
    public Dictionary<Vector2, float> wasteDeteriorationByTile = new Dictionary<Vector2, float>();
    public Dictionary<Vector2, float> powerDeteriorationByTile = new Dictionary<Vector2, float>();

    private const int PRISON_DETERIORATION_RATE = -1;
    private const int FOOD_DETERIORATION_RATE = -2;
    private const int SAFETY_DETERIORATION_RATE = -2;
    private const float UTILITIES_DETERIORATION_RATE = -0.5f;
    
    public List<Building.BuildingType> buildingTypesAlreadyInCity = new List<Building.BuildingType>();
    private Dictionary<Building.BuildingType, List<Vector2>> locationsByBuildingType = new Dictionary<Building.BuildingType, List<Vector2>>();
    private int foodPieceCount = 0;

    private List<District> knownDistricts = new List<District>();
    private Dictionary<Vector2, District> districtMembership = new Dictionary<Vector2, District>();

    private bool advancedMode = false;
    private int removals = 0;

    public string ScoreSummary { get; private set; }
    private StringBuilder scoreTracker;
    public int turnCount = 0;

    public CityScore(City city, bool advancedMode)
    {
        this.city = city;
        this.advancedMode = advancedMode;

        lowerDifficultyInteractions = LoadDifficulties("Assets\\lowerDifficultyInteractions.csv");
        upperDifficultyInteractions = LoadDifficulties("Assets\\upperDifficultyInteractions.csv");

    }

    private static Dictionary<string, Dictionary<string, int>> LoadDifficulties(string source)
    {
        StringBuilder loadBuilder = new StringBuilder();
        StringBuilder scoreDataBuilder = new StringBuilder();

        Dictionary<string, Dictionary<string, int>> loadedValues = new Dictionary<string, Dictionary<string, int>>();

        DataTable table = CsvToDataTable.Load(source);

        List<string> topRow = new List<string>();
        DataRow namesRow = table.Rows[0];
        for (int column = 1; column < table.Columns.Count; column++)
        {
            loadBuilder.AppendLine("read " + table.Columns[column].ColumnName + " into top line");
            topRow.Add(table.Columns[column].ColumnName.Replace(" ", "_"));
        }

        for (int row = 1; row < table.Rows.Count; row++)
        {
            string currentBuildingName = table.Rows[row][0].ToString().Replace(' ', '_');
            loadBuilder.AppendLine("Reading data for " + currentBuildingName);
            loadedValues.Add(currentBuildingName, new Dictionary<string, int>());
            int readColumn = 1;
            foreach (string topRowName in topRow)
            {
                loadBuilder.AppendLine("Adding data for " + currentBuildingName + ", " + topRowName);
                scoreDataBuilder.AppendFormat("'{0}', '{1}', {2}\n", currentBuildingName, topRowName, table.Rows[row][readColumn]);
                loadedValues[currentBuildingName].Add(topRowName, Convert.ToInt32(table.Rows[row][readColumn++]));
            }
        }

        UnityEngine.MonoBehaviour.print(loadBuilder.ToString());
        UnityEngine.MonoBehaviour.print(scoreDataBuilder.ToString());
        return loadedValues;
    }

    /// <summary>
    /// Adjust the score based on surrounding data. The city has already been modified at this point.
    /// </summary>
    /// <param name="buildingEvent"></param>
    public void ProcessEvent(BuildingEvent buildingEvent)
    {
        turnCount++;
        scoreTracker = new StringBuilder();
        float previousScore = score;

        // A building has either been created or destroyed at a given location. 
        // Based on what's around it,
        // and what's already in the city,
        // modify the score according to the rules.
        if (buildingEvent.type == BuildingEvent.BuildingEventType.Create)
        {
            // Update locations-by-type index
            foreach (Vector2 location in buildingEvent.locations)
            {
                UnityEngine.MonoBehaviour.print("Adding type " + buildingEvent.building.type + " at location " + location);
                if (!locationsByBuildingType.ContainsKey(buildingEvent.building.type)) locationsByBuildingType.Add(buildingEvent.building.type, new List<Vector2>());
                if (!locationsByBuildingType[buildingEvent.building.type].Contains(location))
                    locationsByBuildingType[buildingEvent.building.type].Add(location);
            }

            scoreTracker.AppendFormat("Adding a building of type {0} at the following locations: ", buildingEvent.building.type);
            foreach (Vector2 location in buildingEvent.locations)
            {
                scoreTracker.AppendFormat("{0} ", location);
            }
            scoreTracker.AppendLine();

            // 1. Unique buildings
            if (!buildingTypesAlreadyInCity.Contains(buildingEvent.building.type))
            {
                scoreTracker.AppendFormat("First building of type {0} placed, 10 point bonus\n", buildingEvent.building.type);
                buildingTypesAlreadyInCity.Add(buildingEvent.building.type);
            }



            // 2. Interaction scores, stored explicitly.
            float interactionScore = GetInteractionScores(buildingEvent);

            // It doesn't matter which tile of the building we use; the key
            // is that we only use one, and since we know we'll always have
            // at least one, it makes sense to use the first in the list.
            Vector2 primaryLocation = buildingEvent.locations[0];   

            // There should never be an entry already existing for this location.
            interactionScoresByTile.Add(primaryLocation, interactionScore);



            // As an assist for the deterioration process, update the farm/ranch stats ahead of time.
            if (buildingEvent.building.type == Building.BuildingType.Farm || buildingEvent.building.type == Building.BuildingType.Ranch)
            {
                foodPieceCount++;
            }

            // 4. Check for districts that have been newly created by this addition, or add to existing districts
            bool addedToDistrict = false;

            foreach (District district in knownDistricts)
            {
                foreach (Vector2 location in buildingEvent.locations)
                {
                    if (addedToDistrict = district.TryAddTile(location))
                    {
                        scoreTracker.AppendFormat("Building added to existing district of type {0}\n", district.Type);
                        break;
                    }
                }
                if (addedToDistrict)
                {
                    foreach (Vector2 location in buildingEvent.locations)
                    {
                        district.ForceAddTile(location);
                        districtMembership.Add(location, district);
                    }
                }
            }
            if (!addedToDistrict)
            {
                District newDistrict = District.CreateFromTile(city, buildingEvent.locations[0]);
                if (newDistrict != null)
                {
                    scoreTracker.AppendFormat("New district of type {0} created!\n", newDistrict.Type);
                    knownDistricts.Add(newDistrict);
                }
            }

        }
        else
        {
            // Update locations-by-type index
            foreach (Vector2 location in buildingEvent.locations)
            {
                UnityEngine.MonoBehaviour.print("Removing type " + buildingEvent.building.type + " from location " + location);
                // location should be in locationsByBuildingType[buildingEvent.building.type], always
                locationsByBuildingType[buildingEvent.building.type].Remove(location);

                // Keep the data clean; remove keys with empty lists
                if (locationsByBuildingType[buildingEvent.building.type].Count == 0)
                    locationsByBuildingType.Remove(buildingEvent.building.type);
            }

            bool typeStillExists = false;
            foreach (Vector2 cityLocation in city.BuildingsByTile.Keys)
            {
                if (city.GetBuilding(cityLocation).type == buildingEvent.building.type)
                {
                    typeStillExists = true;
                    break;
                }
            }
            if (!typeStillExists)
            {
                buildingTypesAlreadyInCity.Remove(buildingEvent.building.type);
            }

            Vector2 primaryLocation = buildingEvent.locations[0];
            float interactionScore = interactionScoresByTile[primaryLocation];
            scoreTracker.AppendFormat("Interaction score {0} removed\n", interactionScore);

            // Should always be one entry per location here.
            interactionScoresByTile.Remove(primaryLocation);


            // In advanced mode, reduce score by an additional 5 per removal
            removals++;

            // Update districts
            District removeDistrict = null;
            foreach (District district in knownDistricts)
            {
                if (!district.IsValidAfterRemoval(buildingEvent.locations))
                {
                    removeDistrict = district;
                    break;
                }
            }
            if (removeDistrict != null)
            {
                scoreTracker.AppendFormat("District of type {0} broken, bonus discarded\n", removeDistrict.Type);
                knownDistricts.Remove(removeDistrict);
            }


            // As an assist for the deterioration process, update the farm/ranch stats ahead of time.
            if (buildingEvent.building.type == Building.BuildingType.Farm || buildingEvent.building.type == Building.BuildingType.Ranch)
            {
                foodPieceCount--;
            }
       
        }

        // Apply deterioration penalties if there are 15 or more buildings in the city
        if (city.BuildingCount > 15)
        {
            scoreTracker.AppendLine("Updating deterioration elements");
            UpdateDeterioration();
        }


        scoreTracker.AppendLine();
        scoreTracker.AppendLine("Score summary: ");

        float interactionTotal = 0;
        foreach (Vector2 interactionTile in interactionScoresByTile.Keys)
        {
            interactionTotal += interactionScoresByTile[interactionTile];
        }
        scoreTracker.AppendFormat("Total building interaction score is {0}\n", interactionTotal);

        float firstPlacementBonus = 0;
        firstPlacementBonus = buildingTypesAlreadyInCity.Count * 10;
        scoreTracker.AppendFormat("First-placement bonus total is {0} for {1} unique types\n", firstPlacementBonus, buildingTypesAlreadyInCity.Count);

        float policeDeteriorationPenalty = 0;
        float fireDeteriorationPenalty = 0;
        float hospitalDeteriorationPenalty = 0;
        float waterDeteriorationPenalty = 0;
        float wasteDeteriorationPenalty = 0;
        float powerDeteriorationPenalty = 0;

        foreach (Vector2 tile in policeDeteriorationByTile.Keys) policeDeteriorationPenalty += policeDeteriorationByTile[tile];
        foreach (Vector2 tile in fireDeteriorationByTile.Keys) fireDeteriorationPenalty += fireDeteriorationByTile[tile];
        foreach (Vector2 tile in hospitalDeteriorationByTile.Keys) hospitalDeteriorationPenalty += hospitalDeteriorationByTile[tile];
        foreach (Vector2 tile in waterDeteriorationByTile.Keys) waterDeteriorationPenalty += waterDeteriorationByTile[tile];
        foreach (Vector2 tile in wasteDeteriorationByTile.Keys) wasteDeteriorationPenalty += wasteDeteriorationByTile[tile];
        foreach (Vector2 tile in powerDeteriorationByTile.Keys) powerDeteriorationPenalty += powerDeteriorationByTile[tile];

        scoreTracker.AppendFormat("Total Police deterioration penalty: {0}\n", policeDeteriorationPenalty);
        scoreTracker.AppendFormat("Total Fire deterioration penalty: {0}\n", fireDeteriorationPenalty);
        scoreTracker.AppendFormat("Total Hospital deterioration penalty: {0}\n", hospitalDeteriorationPenalty);
        scoreTracker.AppendFormat("Total Water deterioration penalty: {0}\n", waterDeteriorationPenalty);
        scoreTracker.AppendFormat("Total Waste deterioration penalty: {0}\n", wasteDeteriorationPenalty);
        scoreTracker.AppendFormat("Total Power deterioration penalty: {0}\n", powerDeteriorationPenalty);

        float totalDeteriorationPenalty = 
            policeDeteriorationPenalty +
            fireDeteriorationPenalty +
            hospitalDeteriorationPenalty +
            waterDeteriorationPenalty +
            wasteDeteriorationPenalty +
            powerDeteriorationPenalty;
        scoreTracker.AppendFormat("Total deterioration penalty: {0}\n", totalDeteriorationPenalty);

        float districtBonus = 0;
        scoreTracker.AppendLine();
        scoreTracker.AppendFormat("Known districts: {0}\n", knownDistricts.Count);
        foreach (District district in knownDistricts)
        {
            scoreTracker.AppendFormat("Type {0}, score {1}\n", district.Type, district.GetDistrictScore());
            districtBonus += district.GetDistrictScore();
        }
        scoreTracker.AppendFormat("Total district bonus: {0}", districtBonus);

        float removalPenalty = 0;
        if (advancedMode)
        {
            removalPenalty = removals * -5;
            scoreTracker.AppendLine();
            scoreTracker.AppendFormat("Removal penalty {0} for {1} removals\n", removalPenalty, removals);
        }

        scoreTracker.AppendLine();
        score = interactionTotal + firstPlacementBonus + totalDeteriorationPenalty + districtBonus + removalPenalty;
        scoreTracker.AppendFormat("FINAL SCORE FOR THIS TURN IS: {0}\n", score);

        ScoreSummary = scoreTracker.ToString();
    }

    private int GetSquareDistance(Vector2 source, Vector2 destination)
    {
        int xDistance = (int)Math.Abs(source.x - destination.x);
        int yDistance = (int)Math.Abs(source.y - destination.y);

        if (xDistance > yDistance) return xDistance;
        return yDistance;
    }

    private bool InRangeOfType(Vector2 tile, Building.BuildingType type, int maxRange)
    {
        if (!locationsByBuildingType.Keys.Contains(type)) return false;
        bool inRange = false;
        foreach (Vector2 typeTile in locationsByBuildingType[type])
        {
            if (GetSquareDistance(tile, typeTile) <= maxRange)
            {
                inRange = true;
                break;
            }
        }
        return inRange;
    }

    private void UpdateDeterioration()
    {
        // Range-based deterioration, tracked by category
        foreach (Vector2 occupiedPosition in city.BuildingsByTile.Keys)
        {
            bool inPoliceRange = InRangeOfType(occupiedPosition, Building.BuildingType.PoliceStation, 5);
            bool inFireRange = InRangeOfType(occupiedPosition, Building.BuildingType.FireStation, 5);
            bool inHospitalRange = InRangeOfType(occupiedPosition, Building.BuildingType.Hospital, 5);

            bool inWaterRange = InRangeOfType(occupiedPosition, Building.BuildingType.WaterPlant, 6);
            bool inPowerRange = InRangeOfType(occupiedPosition, Building.BuildingType.Hospital, 6);
            bool inGreenPowerRange = InRangeOfType(occupiedPosition, Building.BuildingType.Hospital, 5);
            bool inWasteRange = InRangeOfType(occupiedPosition, Building.BuildingType.Hospital, 6);

            if (!inPoliceRange)
            {
                if (!policeDeteriorationByTile.ContainsKey(occupiedPosition)) policeDeteriorationByTile.Add(occupiedPosition, 0);
                policeDeteriorationByTile[occupiedPosition] += SAFETY_DETERIORATION_RATE;
                scoreTracker.AppendFormat("Police deterioration for tile {0} now at {1}", occupiedPosition, policeDeteriorationByTile[occupiedPosition]);
            }

            if (!inFireRange)
            {
                if (!fireDeteriorationByTile.ContainsKey(occupiedPosition)) fireDeteriorationByTile.Add(occupiedPosition, 0);
                fireDeteriorationByTile[occupiedPosition] += SAFETY_DETERIORATION_RATE;
                scoreTracker.AppendFormat("Fire deterioration for tile {0} now at {1}", occupiedPosition, fireDeteriorationByTile[occupiedPosition]);
            }

            if (!inHospitalRange)
            {
                if (!hospitalDeteriorationByTile.ContainsKey(occupiedPosition)) hospitalDeteriorationByTile.Add(occupiedPosition, 0);
                hospitalDeteriorationByTile[occupiedPosition] += SAFETY_DETERIORATION_RATE;
                scoreTracker.AppendFormat("Hospital deterioration for tile {0} now at {1}", hospitalDeteriorationByTile, policeDeteriorationByTile[occupiedPosition]);
            }

            if (!inWaterRange)
            {
                if (!waterDeteriorationByTile.ContainsKey(occupiedPosition)) waterDeteriorationByTile.Add(occupiedPosition, 0);
                waterDeteriorationByTile[occupiedPosition] += UTILITIES_DETERIORATION_RATE;
                scoreTracker.AppendFormat("Water deterioration for tile {0} now at {1}", occupiedPosition, waterDeteriorationByTile[occupiedPosition]);
            }

            if (!inWasteRange)
            {
                if (!wasteDeteriorationByTile.ContainsKey(occupiedPosition)) wasteDeteriorationByTile.Add(occupiedPosition, 0);
                wasteDeteriorationByTile[occupiedPosition] += UTILITIES_DETERIORATION_RATE;
                scoreTracker.AppendFormat("Waste deterioration for tile {0} now at {1}", occupiedPosition, wasteDeteriorationByTile[occupiedPosition]);
            }

            if (!inPowerRange && !inGreenPowerRange)
            {
                if (!powerDeteriorationByTile.ContainsKey(occupiedPosition)) powerDeteriorationByTile.Add(occupiedPosition, 0);
                powerDeteriorationByTile[occupiedPosition] += UTILITIES_DETERIORATION_RATE;
                scoreTracker.AppendFormat("Power deterioration for tile {0} now at {1}", occupiedPosition, powerDeteriorationByTile[occupiedPosition]);
            }

        }



        // Farmland: -2 per turn of inadequate farmland.

        // One food piece required per 1/6 of city filled; 1/6 of city is (city.width * city.height / 6).
        // Amount of city filled is city.BuildingsByTile.Keys.Count.
        int requiredFoodPieces = city.BuildingsByTile.Keys.Count / (city.width * city.height / 6);
        if (requiredFoodPieces > foodPieceCount)
        {
            foodDeteriorationPenalty += FOOD_DETERIORATION_RATE;
            scoreTracker.AppendFormat("Deterioration penalty for insufficient food: {0}\n", foodDeteriorationPenalty);
        }
        else
        {
            if (foodDeteriorationPenalty > 0)
            {
                scoreTracker.AppendFormat("Deterioration penalty for insufficient food removed\n");
            }
            foodDeteriorationPenalty = 0;
        }



        // Prison - -1 per turn of no prison after the game board is 1/2 full.
        if (buildingTypesAlreadyInCity.Contains(Building.BuildingType.Prison))
        {
            prisonDeteriorationPenalty = 0;
            scoreTracker.AppendFormat("Deterioration penalty for lacking prison is 0");
        }
        else
        {
            if (city.BuildingsByTile.Keys.Count > city.width * city.height / 2)
            {
                prisonDeteriorationPenalty += PRISON_DETERIORATION_RATE;
                scoreTracker.AppendFormat("Deterioration penalty for no prison after city is half built: {0}\n", prisonDeteriorationPenalty);
            }
        }


    }

    private float GetInteractionScores(BuildingEvent buildingEvent)
    {
        float interactionScore = 0;

        // 1. Get all tiles affected and the minimum distance from the new building to each one
        Dictionary<Vector2, int> tilesAffected = new Dictionary<Vector2, int>();
        int areaOfEffect = buildingEvent.building.areaOfEffect;
        foreach (Vector2 buildingTile in buildingEvent.locations)
        {
            for (int x = (int)buildingTile.x - areaOfEffect; x <= (int)buildingTile.x + areaOfEffect; x++)
            {
                for (int y = (int)buildingTile.y - areaOfEffect; y <= (int)buildingTile.y + areaOfEffect; y++)
                {
                    Vector2 location = new Vector2(x, y);
                    if (!buildingEvent.locations.Contains(location))
                    {
                        int distance = (int)Math.Max(Math.Abs((int)buildingTile.x - x), Math.Abs((int)buildingTile.y - y));
                        if (!tilesAffected.ContainsKey(location)) 
                        {
                            tilesAffected.Add(location, distance);
                        } 
                        else 
                        {
                            if (tilesAffected[location] > distance)
                                tilesAffected[location] = distance;
                        }
                    }

                }
            }
        }

        foreach (Vector2 tileAffected in tilesAffected.Keys)
        {
            //scoreTracker.AppendFormat("Tile {0} affected by placement, distance is {1}\n", tileAffected, tilesAffected[tileAffected]);
        }


        // 2. Iterate all tiles affected to find building effects, using the largest distance in range
        Dictionary<Building, float> relationshipFactors = new Dictionary<Building, float>();
        foreach (Vector2 tileAffected in tilesAffected.Keys)
        {
            Building building = city.GetBuilding(tileAffected);
            if (building != null)
            {
                int distance = tilesAffected[tileAffected];
                if (!relationshipFactors.ContainsKey(building))
                {
                    relationshipFactors.Add(building, distance);
                }
                else
                {
                    if (distance > relationshipFactors[building])
                        relationshipFactors[building] = distance;
                }
            }
        }

        // Currently the dictionary stores the greatest affected distance for each building.
        // Distance of 1 yields 1, 2 yields 0.5, 3 yields 0.25, 4 yields 0.125:
        // = 1 / 2^(distance - 1)
        Dictionary<Building, float> distanceFactors = new Dictionary<Building, float>();
        foreach (Building building in relationshipFactors.Keys)
        {
            distanceFactors.Add(building, 1f / (float)Math.Pow(2, relationshipFactors[building] - 1));
        }

        scoreTracker.AppendLine();
        // 3. Accumulate the score
        // Each building affected by the placement adds its relationship factor * distance factor
        foreach (Building building in distanceFactors.Keys)
        {
            string newBuildingName = GetBuildingScoreName(buildingEvent.building.type);
            string relatedBuildingName = GetBuildingScoreName(building.type);

            UnityEngine.MonoBehaviour.print(string.Format("relationship between {0} and {1}, advanced mode is {2}", newBuildingName, relatedBuildingName, advancedMode));

            int baseFactor = 1;
            if (advancedMode)
            {
                baseFactor = upperDifficultyInteractions[newBuildingName][relatedBuildingName];
            }
            else
            {
                baseFactor = lowerDifficultyInteractions[newBuildingName][relatedBuildingName];
            }

            float trueFactor = baseFactor * distanceFactors[building];
            scoreTracker.AppendFormat("Building type {0} affected by base factor {1} * distance factor {2} = total factor {3}\n", building.type, baseFactor, distanceFactors[building], trueFactor);
            interactionScore += trueFactor;
        }
        scoreTracker.AppendLine();

        scoreTracker.AppendFormat("Total score change based on interactions is {0}\n", interactionScore);

        return interactionScore;
    }

    private string GetBuildingScoreName(Building.BuildingType buildingType)
    {
        switch (buildingType)
        {
            case Building.BuildingType.Banks:
                return "Banks";
            case Building.BuildingType.BigBoxStore:
                return "Big_Box_Stores";
            case Building.BuildingType.BusinessPark:
                return "Business_Park";
            case Building.BuildingType.Capital:
                return "Capital";
            case Building.BuildingType.Church:
                return "Church";
            case Building.BuildingType.Communications:
                return "Communications";
            case Building.BuildingType.Courthouse:
                return "Courthouse";
            case Building.BuildingType.Empty:
                return "None";
            case Building.BuildingType.EmptyRubble:
                return "None";
            case Building.BuildingType.Factory:
                return "Factory";
            case Building.BuildingType.Farm:
                return "Farm";
            case Building.BuildingType.FireStation:
                return "Fire";
            case Building.BuildingType.Fuel:
                return "Fuel";
            case Building.BuildingType.GreenPower:
                return "Green_Power";
            case Building.BuildingType.Hospital:
                return "Hospital";
            case Building.BuildingType.House:
                return "Urban";
            case Building.BuildingType.Library:
                return "Library";
            case Building.BuildingType.Lumber:
                return "Lumber";
            case Building.BuildingType.Mining:
                return "Mining";
            case Building.BuildingType.Museum:
                return "Museum";
            case Building.BuildingType.Park:
                return "Park";
            case Building.BuildingType.PoliceStation:
                return "Law_Enforcement";
            case Building.BuildingType.PowerStation:
                return "Power";
            case Building.BuildingType.PrimarySchool:
                return "Primary_School";
            case Building.BuildingType.Prison:
                return "Prison";
            case Building.BuildingType.Ranch:
                return "Ranch";
            case Building.BuildingType.Restaurants:
                return "Restaurants";
            case Building.BuildingType.SecondarySchool:
                return "Secondary_School";
            case Building.BuildingType.Stadium:
                return "Stadium";
            case Building.BuildingType.Suburban:
                return "Suburban";
            case Building.BuildingType.Textiles:
                return "Textile";
            case Building.BuildingType.Theater:
                return "Theater";
            case Building.BuildingType.Urban:
                return "Urban";
            case Building.BuildingType.Warehouse:
                return "Warehouses";
            case Building.BuildingType.Waste:
                return "Waste";
            case Building.BuildingType.WaterPlant:
                return "Water";
            case Building.BuildingType.Zoo:
                return "Zoo";
        }
        return string.Empty;
    }

    public float Score { get { return score; } }
}
